package com.wenwen.social.application.impl;

import cn.hutool.core.bean.BeanUtil;
import com.wenwen.social.application.FollowApplication;
import com.wenwen.social.application.dto.FansDTO;
import com.wenwen.social.application.dto.FollowingsDTO;
import com.wenwen.social.application.dto.PageRequest;
import com.wenwen.social.application.dto.PageResult;
import com.wenwen.social.common.exception.ServiceException;
import com.wenwen.social.constant.errorcode.CommonErrorConstant;
import com.wenwen.social.domain.model.*;
import com.wenwen.social.domain.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.temporal.TemporalField;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.wenwen.social.constant.FansConstant.FANS_TYPE;
import static com.wenwen.social.constant.FollowConstant.FOLLOWINGS_TYPE;
import static com.wenwen.social.constant.FollowConstant.FOLLOW_LIMIT_NUM;
import static com.wenwen.social.constant.errorcode.CommonErrorConstant.*;
import static java.util.stream.Collectors.toList;

@Service
public class FollowApplicationImpl implements FollowApplication {
	@Autowired
	private FollowService followService;
	@Autowired
	private FansService fansService;
	@Autowired
	private FollowLineService followLineService;

	@Autowired
	private PersonLineService personLineService;
	@Autowired
	private HomeLineService homeLineService;
	@Autowired
	private UserService userService;

	@Override
	public void follow(Long uid ,List<Long> list){
			list.remove(uid);
			list.stream().filter(t-> t!=null)
					.filter(t->t != null)
					.filter(t -> !followService.existFollowings(uid, System.currentTimeMillis()))
					.forEach(t->addfollowingsUid(uid,t));
		return;
	}

	private void addfollowingsUid(Long uid, Long t) {
		followService.add(uid,t);
		fansService.add(t,uid);
		//更改关注数
		updateFollowing(uid,FOLLOWINGS_TYPE,1);
		//更改被关注数
		updateFans(t,FANS_TYPE,1);
		//添加至时间线
		//关注时间线
		//获取关注人的最近10条消息id
		List<PersonLine> query = personLineService.query(t,1, FOLLOW_LIMIT_NUM);
		for (PersonLine personLine : query) {
			followLineService.add(t,new FollowLine(personLine.getMessageId(),personLine.getTime()));
			homeLineService.add(t,new HomeLine(personLine.getMessageId(),personLine.getTime()));
		}
		//截取时间线前1000条记录
		Long count = followLineService.count(uid);
		if(count>FOLLOW_LIMIT_NUM){
			followLineService.limit(uid,0,FOLLOW_LIMIT_NUM);
		}
	}

	public Integer unfollow(Long uid,Long followUid){
		boolean existFans = followService.existFollowings(uid, followUid);
		if (existFans){
			followService.del(uid,followUid);
			fansService.del(followUid,uid);

			updateFollowing(uid,FOLLOWINGS_TYPE,-1);
			updateFans(followUid,FANS_TYPE,-1);

			//修改主页时间线与关注时间线
			//获取message最新1000条信息，获取msgId，删除
			List<PersonLine> query = personLineService.query(followUid, 0, FOLLOW_LIMIT_NUM);
			if(query == null || query.isEmpty()) return 0;
			List<Long> collect = query.stream().map(t -> t.getMessageId()).collect(toList());
			followLineService.del(uid,collect);

			homeLineService.del(uid,collect);
			return 1;
		}
		return 0;
	}

	@Override
	public PageResult<FansDTO> queryFans(Long uid, PageRequest pageRequest) {
		Integer page = pageRequest.getPageNum();
		Integer num = pageRequest.getPageSize();
		User user = userService.getUser(uid);
		if(user == null ) {
			throw new ServiceException(CommonErrorConstant.USER_NOT_EXIST_CODE, USER_NOT_EXIST_MSG);
		}

		Long count = countFans(uid);
		if(count == null||count == 0){
			return new PageResult<>(new ArrayList<>(),page,num,0);
		}

		List<FansDTO> fansDTO = getFansDTO(uid, page, num);
		if(fansDTO == null || fansDTO.isEmpty()){
			return new PageResult<>(new ArrayList<>(),page,num,0);
		}

		return new PageResult<>(fansDTO, pageRequest.getPageNum(), pageRequest.getPageSize(), count.intValue());
	}


	@Override
	public  PageResult<FollowingsDTO> queryFollowings(Long uid, PageRequest pageRequest) {
		Integer page = pageRequest.getPageNum();
		Integer num = pageRequest.getPageSize();
		User user = userService.getUser(uid);
		if(user == null ) {
			throw new ServiceException(CommonErrorConstant.USER_NOT_EXIST_CODE, USER_NOT_EXIST_MSG);
		}

		Long count = countFollowings(uid);
		if(count == null||count == 0){
			return new PageResult<>(new ArrayList<>(),page,num,0);
		}

		List<FollowingsDTO> followingsDTO = getFollowingsDTO(uid, page, num);
		if(followingsDTO == null || followingsDTO.isEmpty()){
			return new PageResult<>(new ArrayList<>(),page,num,0);
		}

		return new PageResult<>(followingsDTO, pageRequest.getPageNum(), pageRequest.getPageSize(), count.intValue());
	}

	private Long countFollowings(Long uid){
		return followService.count(uid);
	}
	private Long countFans(Long uid){
		return fansService.count(uid);
	}

	private List<FollowingsDTO> getFollowingsDTO(Long uid, Integer page, Integer num){
		Follow follow = followService.queryFollowings(uid, page, num);

		if(follow==null)
			return new ArrayList<>();
		Map<Long, Long> followMap = follow.getFollowMap();
		if(followMap == null || followMap.isEmpty())
			return new ArrayList<>();
		List<Long> uidList  = new ArrayList<>(followMap.keySet());

		List<User> users = userService.getUsers(uidList);

		return convertFollowingsDTOList(users,followMap);
	}

	private List<FansDTO> getFansDTO(Long uid, Integer page, Integer num){
		Fans fans = fansService.queryFans(uid, page, num);

		if(fans==null)
			return new ArrayList<>();
		Map<Long, Long> fansMap = fans.getFansMap();
		if(fansMap == null || fansMap.isEmpty())
			return new ArrayList<>();
		List<Long> uidList  = new ArrayList<>(fansMap.keySet());

		List<User> users = userService.getUsers(uidList);
		if(users == null || users.isEmpty()){
			return new ArrayList<>();
		}
		return convertFansDTOList(users,fansMap);
	}


	private List<FansDTO> convertFansDTOList(List<User> users, Map<Long, Long> followMap) {
		List<FansDTO> fansDTOList = new ArrayList<>();
		users.stream().filter(t->t!=null&&t.getId()!=null).forEach(t->{
			FansDTO fansDTO = new FansDTO();
			BeanUtil.copyProperties(t,fansDTO);
			Long time = followMap.get(t.getId());
			Date fansTime = new Date(time);
			fansDTO.setBeFansTime(fansTime);
			fansDTOList.add(fansDTO);
		});
		return fansDTOList;
	}

	private List<FollowingsDTO> convertFollowingsDTOList(List<User> users, Map<Long, Long> followMap) {
		List<FollowingsDTO> followingsDTOList = new ArrayList<>();
		users.stream().filter(t->t!=null&&t.getId()!=null).forEach(t->{
			FollowingsDTO followingsDTO = new FollowingsDTO();
			BeanUtil.copyProperties(t,followingsDTO);
			Long time = followMap.get(t.getId());
			Date followTime = new Date(time);
			followingsDTO.setFollowingsTime(followTime);
			followingsDTOList.add(followingsDTO);
		});
		return followingsDTOList;
	}


	private void updateFans(Long fan, int followersType,int changeNum) {
		updateUserProp(fan,followersType,changeNum);
	}
	private void updateFollowing(Long uid,int type,int changeNum) {
		updateUserProp(uid,type, changeNum);
	}
	private void updateUserProp(Long uid,int type,int changeNum){
		User user = userService.getUser(uid);
		if(user == null) {
			throw new ServiceException(USER_NOT_EXIST_CODE,USER_NOT_EXIST_MSG);
		}
		if(type == FOLLOWINGS_TYPE) {
			user.setFollowings(user.getFollowings()+changeNum);
		}else if(type ==FANS_TYPE){
			user.setFollowers(user.getFollowers()+changeNum);
		}
		userService.updateUser(user);
	}
}
